package com.utils

import com.jcraft.jsch.*
import com.subpackage.BasePack
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.text.DecimalFormat
import java.util.*

/**
 * sftp工具。注意：构造方法有两个：分别是基于密码认证、基于秘钥认证。
 *
 * @author boges
 */
class SFTPUtil : BasePack {
    private val logger: Logger = LoggerFactory.getLogger(javaClass)

    private var sftp: ChannelSftp? = null

    private var session: Session? = null

    /**
     * FTP 登录用户名
     */
    private var username: String? = null

    /**
     * FTP 登录密码
     */
    private var password: String? = null

    /**
     * 私钥文件的路径
     */
    private var keyFilePath: String? = null

    /**
     * FTP 服务器地址IP地址
     */
    private var host: String? = null

    /**
     * FTP 端口
     */
    private var port = 0


    /**
     * 构造基于密码认证的sftp对象
     *
     * @param username 账户名字
     * @param password 账户密码
     * @param host     主机ip
     * @param port     主机端口
     */
    constructor(username: String?, password: String?, host: String?, port: Int) {
        this.username = username
        this.password = password
        this.host = host
        this.port = port
    }

    /**
     * 构造基于秘钥认证的sftp对象
     *
     * @param username
     * @param host
     * @param port
     * @param keyFilePath
     */
    constructor(username: String?, host: String?, port: Int, keyFilePath: String?) {
        this.username = username
        this.host = host
        this.port = port
        this.keyFilePath = keyFilePath
    }

    constructor()

    /**
     * 连接sftp服务器
     *
     * @throws Exception
     */
    fun login(): Boolean {
        try {
            val jsch = JSch()
            if (keyFilePath != null) {
                jsch.addIdentity(keyFilePath) // 设置私钥
                println("sftp connect,path of private key file：$keyFilePath")
            }
            println("sftp connect by host:$host username: $username")

            session = jsch.getSession(username, host, port)
            println("Session is build")
            if (password != null) {
                session?.setPassword(password)
            }
            val config = Properties()
            config["StrictHostKeyChecking"] = "no"

            session?.setConfig(config)
            session?.connect()
            println("Session is connected")

            val channel = session?.openChannel("sftp")
            channel!!.connect()
            println("channel is connected")

            sftp = channel as ChannelSftp
            println(String.format("sftp server host:[%s] port:[%s] is connect successfull", host, port))
            return true
        } catch (e: JSchException) {
            println(
                """Cannot connect to specified sftp server : $host:$port 
 Exception message is: ${e.message}"""
            )
            //            throw new BizException(e.getMessage(),e);
            return false
        }
    }

    /**
     * 关闭连接 server
     */
    fun logout() {
        if (sftp?.isConnected == true) {
            sftp?.disconnect()
            println("sftp is closed already")
        }
        if (session?.isConnected == true) {
            session?.disconnect()
            println("sshSession is closed already")
        }
    }

    /**
     * 上传文件
     *
     * @param str 本地文件路径
     * @param dir 远程文件路径
     * @return
     */
    fun upload(str: String, dir: String): Boolean {
        val file = File(str)
        logger.info("本地文件路径 = $str | 远程文件路径 = $dir")
        if (file.exists()) {
            try {
                val fis = FileInputStream(file)
                val parent = File(dir).parentFile.path
                val folders = parent.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                sftp!!.cd("/")
                for (folder in folders) {
                    if (folder.isNotEmpty()) {
                        try {
                            sftp!!.cd(folder)
                            //                        System.out.println(sftp.pwd()+"\n ******************");
                        } catch (e: SftpException) {
                            logger.info("文件夹不存在新建=$folder")
                            sftp!!.mkdir(folder)
                            sftp!!.cd(folder)
                        }
                    }
                }
                //            sftp.put(fis, dir, new MyProgressMonitor(fis.available()));
                sftp!!.put(fis, dir)
                return true
            } catch (e: Exception) {
                logger.error(e.message, e)
                return false
            }
        } else {
            logger.info("此文件不存在了!无法上传=" + file.path)
            return true
        }
    }

    @Suppress("UNCHECKED_CAST")
    fun upload(updateList: List<String>, parentPath: String): Boolean {
        val appConfig = YamlUtil.getAppConfig()
        val env = appConfig.user[YamlUtil.unpackEnvName]!!
        val sftpMap = env["sftp"] as Map<String, String>
        val uploadSFTPPath = sftpMap["uploadSFTPPath"]!!

        var path: String
        val total = updateList.size
        for (i in updateList.indices) {
            val localStr = updateList[i]
            path = uploadSFTPPath + localStr
            path = path.replace(parentPath, "")
//            logger.info("update sftp: localStr = " + localStr + ", parentPath = " + parentPath + ", path = " + path);
            if (!upload(localStr, path)) {
                return false
            }
            val d = (i.toDouble() / total) * 100
            val df = DecimalFormat("#.##")
            print("\r")
            print("上传进度: " + df.format(d) + "%")

        }
        print("\r")
        println("上传进度: 100%")
        return true
    }

    /**
     * 判断是否存在此文件
     *
     * @param directory
     * @return
     */
    fun isFileExist(directory: String?): Boolean {
        try {
            sftp!![directory]
            return true
        } catch (e: Exception) {
        }
        return false
    }

    /**
     * 下载文件
     *
     * @param downloadFile 下载的文件
     * @param saveFile     存在本地的路径
     */
    fun download(downloadFile: String, saveFile: String?) {
        val file = File(downloadFile)
        sftp!![downloadFile, FileOutputStream(file)]
        println("file:$downloadFile is download successful")
    }

    /**
     * 下载文件
     *
     * @param downloadFile 下载的文件名
     * @return 字节数组
     */
    fun download(downloadFile: String): ByteArray? {
        var fileData: ByteArray? = null
        val inputStream = sftp!![downloadFile]
        fileData = inputStream.readAllBytes()

        println("file:$downloadFile is download successful")
        return fileData
    }

    /**
     * 删除文件
     *
     * @param file 服务完整路径
     * @throws SftpException
     */
    fun delete(file: String?) {
        if (isFileExist(file)) {
            sftp!!.rm(file)
        }
    }

    /**
     * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @return
     * @throws SftpException
     */
    @Throws(SftpException::class)
    fun listFiles(directory: String?): Vector<*> {
        return sftp!!.ls(directory)
    }

    companion object {
        @Throws(SftpException::class, IOException::class)
        @JvmStatic
        fun main(args: Array<String>) {
            val sftp = SFTPUtil("testing", "abcd1234", "192.168.0.178", 22)
            sftp.login()

            //        sftp.delete("/home/testing/workspace/Static2/appGame/update/filetable.bin");
            sftp.upload(
                "/Users/boge/Project/Game/innerWork/appGame/update/assetsid.txt",
                "/home/testing/workspace/Static2/appGame2/update/assetsid.txt"
            )


            //        "/home/testing/workspace/Static2/appGame/update/assetsid.txt");
//        sftp.sftp.put("/Users/boge/Project/test/Readme.txt", "./workspace/Static2", new MyProgressMonitor(1));
            sftp.logout()
        }
    }
}